package com.apobates.jforum.grief.aurl.executor;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import java.net.Authenticator;
import java.net.CookieHandler;
import java.net.ProxySelector;
import java.net.http.HttpClient;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.concurrent.ExecutorService;
import java.util.function.Function;
/**
 * 请求的环境参数
 */
public class HClientContext<T> {
    /**
     * HTTP Version=1.1 返回字符串响应内容
     */
    public static HClientContext<String> defaultConfig = HClientContext.Builder.<String>of(1).bodyHandler(HttpResponse.BodyHandlers.ofString()).build();

    // 连接超时(client)
    private final Duration connectTimeOut; // = Duration.ofSeconds(20);
    // 请求超时(request)
    private final Duration requestTimeOut; // = Duration.ofMinutes(2);
    // http协议的版本(request)
    private final HttpClient.Version version; // = HttpClient.Version.HTTP_1_1;
    // 请求的内容类型(request)
    private final String contentType; // = "text/html; charset=utf-8";
    // 请求的头信息
    private final String[] headers;
    // 请求的查询参数(request)
    private final String queryString; // = "";
    // 是否是异步(request)
    // true同步/false异步
    private final boolean isAsync; // = false;
    // 优先级(client)
    private final int priority; // =1;
    // 异常处理句柄(response)
    private final Function<Exception,HClientResponse> exceptionHander; //  = (e)->HClientResponse.serverError(e.getMessage());
    // 内容的处理句柄(response)
    private final HttpResponse.BodyHandler<T> handler;
    // 异步时响应结果的等待超时时长
    private final Duration responseTimeOut; //  = Duration.ofSeconds(5);
    // 执行器(client)
    private final ExecutorService executorService;
    // 认证器(client)
    private final Authenticator authenticator;
    // Cookie(client)
    private final CookieHandler cookieHandler;
    // SSL证书上下文(client)
    private final SSLContext sslContext;
    // SSL证书参数(client)
    private final SSLParameters sslParameters;
    // 代理(client)
    private final ProxySelector proxy;

    private HClientContext(Builder builder){
        this.connectTimeOut = builder.connectTimeOut; // = Duration.ofSeconds(20);
        // 请求超时(request)
        this.requestTimeOut = builder.requestTimeOut; // = Duration.ofMinutes(2);
        // http协议的版本(request)
        this.version = builder.version; // = HttpClient.Version.HTTP_1_1;
        // 请求的内容类型(request)
        this.contentType = builder.contentType; // = "text/html; charset=utf-8";
        // 请求的头信息
        this.headers = builder.headers;
        // 请求的查询参数(request)
        this.queryString = builder.queryString; // = "";
        // 是否是异步(request)
        // true同步/false异步
        this.isAsync = builder.isAsync;

        this.priority = builder.priority; // =1;
        // 异常处理句柄(response)
        this.exceptionHander = builder.exceptionHander; //  = (e)->HClientResponse.serverError(e.getMessage());
        // 内容的处理句柄(response)
        this.handler = builder.handler;
        // 异步时响应结果的等待超时时长
        this.responseTimeOut = builder.responseTimeOut; //  = Duration.ofSeconds(5);
        // 执行器(client)
        this.executorService = builder.executorService;
        // 认证器(client)
        this.authenticator = builder.authenticator;
        // Cookie(client)
        this.cookieHandler = builder.cookieHandler;
        // SSL证书上下文(client)
        this.sslContext = builder.sslContext;
        // SSL证书参数(client)
        this.sslParameters = builder.sslParameters;
        // 代理(client)
        this.proxy = builder.proxy;
    }

    public Duration getConnectTimeOut() {
        return connectTimeOut;
    }

    public Duration getRequestTimeOut() {
        return requestTimeOut;
    }

    public HttpClient.Version getVersion() {
        return version;
    }

    public String getContentType() {
        return contentType;
    }

    public String[] getHeaders() {
        return headers;
    }

    public String getQueryString() {
        return queryString;
    }

    public boolean isAsync() {
        return isAsync;
    }

    public int getPriority() {
        return priority;
    }

    public Function<Exception, HClientResponse> getExceptionHander() {
        return exceptionHander;
    }

    public HttpResponse.BodyHandler<T> getHandler() {
        return handler;
    }

    public Duration getResponseTimeOut() {
        return responseTimeOut;
    }

    public ExecutorService getExecutorService() {
        return executorService;
    }

    public Authenticator getAuthenticator() {
        return authenticator;
    }

    public CookieHandler getCookieHandler() {
        return cookieHandler;
    }

    public SSLContext getSslContext() {
        return sslContext;
    }

    public SSLParameters getSslParameters() {
        return sslParameters;
    }

    public ProxySelector getProxy() {
        return proxy;
    }

    public static class Builder<T>{
        // 连接超时(client)
        private Duration connectTimeOut = Duration.ofSeconds(20);
        // 请求超时(request)
        private Duration requestTimeOut = Duration.ofMinutes(2);
        // http协议的版本(request)
        private HttpClient.Version version = HttpClient.Version.HTTP_1_1;
        // 请求的内容类型(request)
        private String contentType = "text/html; charset=utf-8";
        // 请求的头信息
        private String[] headers;
        // 请求的查询参数(request)
        private String queryString = "";
        // 是否是异步(request)
        // true同步/false异步
        private boolean isAsync = false;
        // 优先级(client)
        private int priority=1;
        // 异常处理句柄(response)
        private Function<Exception,HClientResponse> exceptionHander = (e)->HClientResponse.serverError(e.getMessage());
        // 内容的处理句柄(response)
        private HttpResponse.BodyHandler<T> handler;
        // 异步时响应结果的等待超时时长
        private Duration responseTimeOut = Duration.ofSeconds(5);
        // 执行器(client)
        private ExecutorService executorService;
        // 认证器(client)
        private Authenticator authenticator;
        // Cookie(client)
        private CookieHandler cookieHandler;
        // SSL证书上下文(client)
        private SSLContext sslContext;
        // SSL证书参数(client)
        private SSLParameters sslParameters;
        // 代理(client)
        private ProxySelector proxy;

        private Builder(){}

        /**
         * 设置请求的Http版本
         * @param version 版本. 只支持: 1或2. 默认为: 1
         * @return
         * @param <T>
         */
        public static <T> Builder<T> of(int version){
            HClientContext.Builder<T> ins = new HClientContext.Builder();
            ins.version = (version == 2)?HttpClient.Version.HTTP_2: HttpClient.Version.HTTP_1_1;
            return ins;
        }

        /**
         * 设置HttpClient的HTTP2请求优先级
         * @param priority The value provided must be between 1 and 256 (inclusive).
         * @return
         */
        public Builder<T> priority(int priority){
            this.priority = priority;
            return this;
        }
        /**
         * 设置HttpClient的连接超时时间
         * @param timeOut 超时时间. 默认为: 20秒
         * @return
         */
        public Builder<T> connectTimeOut(Duration timeOut){
            this.connectTimeOut = timeOut;
            return this;
        }
        /**
         * 设置请求的超时时间
         * @param timeOut 超时时间. 默认为: 2分钟
         * @return
         */
        public Builder<T> requestTimeOut(Duration timeOut){
            this.requestTimeOut = timeOut;
            return this;
        }

        /**
         * 设置请求的内容类型
         * @param contentType 内容类型, 例: application/json, application/x-www-form-urlencoded. 默认为: text/html
         * @return
         */
        public Builder<T> contentType(String contentType){
            this.contentType = contentType;
            return this;
        }

        /**
         * 设置请求的头信息
         * @param headerStrArr 头信息
         * @return
         */
        public Builder<T> headers(String... headerStrArr){
            this.headers = headerStrArr;
            return this;
        }
        /**
         * 设置请求的查询参数
         * @param queryString 查询参数, 例: page=1&pageSize=20. 默认为: 空
         * @return
         */
        public Builder<T> queryString(String queryString){
            this.queryString = queryString;
            return this;
        }

        /**
         * 设置请求是否是异步
         * @param isAsync 异步: true, 同步: false(默认)
         * @return
         */
        public Builder<T> async(boolean isAsync){
            this.isAsync = isAsync;
            return this;
        }

        /**
         * 设置响应的回调
         * @param handler 回调句柄. 默认为: HttpResponse.BodyHandlers.ofString()
         * @return
         */
        public Builder<T> bodyHandler(HttpResponse.BodyHandler<T> handler){
            this.handler = handler;
            return this;
        }

        /**
         * 设置HttpClient的执行器
         * 注意: 只在async=true时有效
         * @param executorService 执行器. 默认为: HttpResponse.BodyHandlers.ofString()
         * @return
         */
        public Builder<T> executorService(ExecutorService executorService){
            if(this.isAsync) {
                this.executorService = executorService;
            }
            return this;
        }

        /**
         * 设置响应的等待超时时长。默认为: 5 SECONDS;
         * 注意: 只在async=true时有效
         * @param timeOut
         * @return
         */
        private Builder<T> responseWaitTimeOut(Duration timeOut){
            if(this.isAsync) {
                this.responseTimeOut = timeOut;
            }
            return this;
        }
        /**
         * 设置HttpClient的Cookie
         * @param cookieHandler
         * @return
         */
        public Builder<T> cookie(CookieHandler cookieHandler){
            this.cookieHandler = cookieHandler;
            return this;
        }

        /**
         * 设置HttpClient的HTTPS 证书上下文
         * @param sslContext
         * @return
         */
        public Builder<T> sslContext(SSLContext sslContext){
            this.sslContext = sslContext;
            return this;
        }

        /**
         * 设置HttpClient的HTTPS 证书参数
         * @param sslParameters
         * @return
         */
        public Builder<T> sslParameters(SSLParameters sslParameters){
            this.sslParameters = sslParameters;
            return this;
        }

        /**
         * 设置HttpClient的认证信息
         * @param authenticator
         * @return
         */
        public Builder<T> authenticator(Authenticator authenticator){
            this.authenticator = authenticator;
            return this;
        }

        /**
         * 设置HttpClient的代理信息
         * @param proxy
         * @return
         */
        public Builder<T> proxy(ProxySelector proxy){
            this.proxy = proxy;
            return this;
        }

        /**
         * 设置响应的异步处理名柄.默认是：返回服务器错误(500)
         * Exception包含
         *  HttpClient.send过程中产生的异常: IOException, InterruptedException, IllegalArgumentException
         *  HttpClient.sendAsync过程中产生的异常: ExecutionException, TimeoutException
         * @param handler
         * @return
         */
        public Builder<T> exceptionHander(Function<Exception,HClientResponse> handler){
            this.exceptionHander = handler;
            return this;
        }

        public HClientContext<T> build(){
            return new HClientContext<>(this);
        }
    }
}
